/*
 * Copyright (c) 2007 empronix (http://www.empronix.com)
 * Author: Benedikt Sauter <sauter@empronix.com>
 * All rights reserved.
 *
 * Short descripton of file:
 *
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above 
 *     copyright notice, this list of conditions and the following 
 *     disclaimer in the documentation and/or other materials provided 
 *     with the distribution.
 *   * Neither the name of the FH Augsburg nor the names of its 
 *     contributors may be used to endorse or promote products derived 
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF USE, 
 * DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdint.h>
#include <avr/io.h>

#include "main.h"
#include "common.h"
#include "protocol.h"
#include "io.h"

//////////////////////////////////////////////////////////////////////////////

#define OX_PIN01	PINE
#define OX_PIN02	PINE
#define OX_PIN03	PINE
#define OX_PIN04	PINB
#define OX_PIN05	PINB
#define OX_PIN06	PINB
#define OX_PIN07	PINB
#define OX_PIN08	PINB
#define OX_PIN09	PINB
#define OX_PIN10	PINB
#define OX_PIN11	PINB
#define OX_PIN12	PIND
#define OX_PIN13	PIND
#define OX_PIN14	PIND
#define OX_PIN15	PIND
#define OX_PIN16	PIND
#define OX_PIN17	PIND
#define OX_PIN18	PIND
#define OX_PIN19	PIND

#define OX_PIN26	PINC
#define OX_PIN27	PINC
#define OX_PIN28	PINC
#define OX_PIN29	PINC
#define OX_PIN30	PINC
#define OX_PIN31	PINC
#define OX_PIN32	PINC
#define OX_PIN33	PINF
#define OX_PIN34	PINF
#define OX_PIN35	PINF
#define OX_PIN36	PINF
#define OX_PIN37	PINF
#define OX_PIN38	PINF
#define OX_PIN39	PINF
#define OX_PIN40	PINF
#define OX_PIN41	PINE
#define OX_PIN42	PINE
#define OX_PIN43	PINE
#define OX_PIN44	PINE

//////////////////////////////////////////////////////////////////////////////

#define OX_PORT01	PORTE
#define OX_PORT02	PORTE
#define OX_PORT03	PORTE
#define OX_PORT04	PORTB
#define OX_PORT05	PORTB
#define OX_PORT06	PORTB
#define OX_PORT07	PORTB
#define OX_PORT08	PORTB
#define OX_PORT09	PORTB
#define OX_PORT10	PORTB
#define OX_PORT11	PORTB
#define OX_PORT12	PORTD
#define OX_PORT13	PORTD
#define OX_PORT14	PORTD
#define OX_PORT15	PORTD
#define OX_PORT16	PORTD
#define OX_PORT17	PORTD
#define OX_PORT18	PORTD
#define OX_PORT19	PORTD

#define OX_PORT26	PORTC
#define OX_PORT27	PORTC
#define OX_PORT28	PORTC
#define OX_PORT29	PORTC
#define OX_PORT30	PORTC
#define OX_PORT31	PORTC
#define OX_PORT32	PORTC
#define OX_PORT33	PORTF
#define OX_PORT34	PORTF
#define OX_PORT35	PORTF
#define OX_PORT36	PORTF
#define OX_PORT37	PORTF
#define OX_PORT38	PORTF
#define OX_PORT39	PORTF
#define OX_PORT40	PORTF
#define OX_PORT41	PORTE
#define OX_PORT42	PORTE
#define OX_PORT43	PORTE
#define OX_PORT44	PORTE

//////////////////////////////////////////////////////////////////////////////

#define OX_DDR01	DDRE
#define OX_DDR02	DDRE
#define OX_DDR03	DDRE
#define OX_DDR04	DDRB
#define OX_DDR05	DDRB
#define OX_DDR06	DDRB
#define OX_DDR07	DDRB
#define OX_DDR08	DDRB
#define OX_DDR09	DDRB
#define OX_DDR10	DDRB
#define OX_DDR11	DDRB
#define OX_DDR12	DDRD
#define OX_DDR13	DDRD
#define OX_DDR14	DDRD
#define OX_DDR15	DDRD
#define OX_DDR16	DDRD
#define OX_DDR17	DDRD
#define OX_DDR18	DDRD
#define OX_DDR19	DDRD

#define OX_DDR26	DDRC
#define OX_DDR27	DDRC
#define OX_DDR28	DDRC
#define OX_DDR29	DDRC
#define OX_DDR30	DDRC
#define OX_DDR31	DDRC
#define OX_DDR32	DDRC
#define OX_DDR33	DDRF
#define OX_DDR34	DDRF
#define OX_DDR35	DDRF
#define OX_DDR36	DDRF
#define OX_DDR37	DDRF
#define OX_DDR38	DDRF
#define OX_DDR39	DDRF
#define OX_DDR40	DDRF
#define OX_DDR41	DDRE
#define OX_DDR42	DDRE
#define OX_DDR43	DDRE
#define OX_DDR44	DDRE

//////////////////////////////////////////////////////////////////////////////

#define OX_P01		PE5
#define OX_P02		PE6
#define OX_P03		PE7
#define OX_P04		PB0
#define OX_P05		PB1
#define OX_P06		PB2
#define OX_P07		PB3
#define OX_P08		PB4
#define OX_P09		PB5
#define OX_P10		PB6
#define OX_P11		PB7
#define OX_P12		PD0
#define OX_P13		PD1
#define OX_P14		PD2
#define OX_P15		PD3
#define OX_P16		PD4
#define OX_P17		PD5
#define OX_P18		PD6
#define OX_P19		PD7

#define OX_P26		PC0
#define OX_P27		PC1
#define OX_P28		PC2
#define OX_P29		PC3
#define OX_P30		PC4
#define OX_P31		PC5
#define OX_P32		PC6
#define OX_P33		PF7
#define OX_P34		PF6
#define OX_P35		PF5
#define OX_P36		PF4
#define OX_P37		PF3
#define OX_P38		PF2
#define OX_P39		PF1
#define OX_P40		PF0
#define OX_P41		PE0
#define OX_P42		PE1
#define OX_P43		PE2
#define OX_P44		PE3

//////////////////////////////////////////////////////////////////////////////

static uint8_t io_pin_set_direction_out (uint8_t pin)
{
	if ((pin >= 1 && pin <= 19) || (pin >= 26 && pin <= 44))
	{
		octopus.ports[pin] = PIN_OUT;
		switch (pin)
		{
		case  1:   OX_DDR01 |= (1<<OX_P01); break;
		case  2:   OX_DDR02 |= (1<<OX_P02); break;
		case  3:   OX_DDR03 |= (1<<OX_P03); break;
		case  4:   OX_DDR04 |= (1<<OX_P04); break;
		case  5:   OX_DDR05 |= (1<<OX_P05); break;
		case  6:   OX_DDR06 |= (1<<OX_P06); break;
		case  7:   OX_DDR07 |= (1<<OX_P07); break;
		case  8:   OX_DDR08 |= (1<<OX_P08); break;
		case  9:   OX_DDR09 |= (1<<OX_P09); break;
		case 10:   OX_DDR10 |= (1<<OX_P10); break;
		case 11:   OX_DDR11 |= (1<<OX_P11); break;
		case 12:   OX_DDR12 |= (1<<OX_P12); break;
		case 13:   OX_DDR13 |= (1<<OX_P13); break;
		case 14:   OX_DDR14 |= (1<<OX_P14); break;
		case 15:   OX_DDR15 |= (1<<OX_P15); break;
		case 16:   OX_DDR16 |= (1<<OX_P16); break;
		case 17:   OX_DDR17 |= (1<<OX_P17); break;
		case 18:   OX_DDR18 |= (1<<OX_P18); break;
		case 19:   OX_DDR19 |= (1<<OX_P19); break;

		case 26:   OX_DDR26 |= (1<<OX_P26); break;
		case 27:   OX_DDR27 |= (1<<OX_P27); break;
		case 28:   OX_DDR28 |= (1<<OX_P28); break;
		case 29:   OX_DDR29 |= (1<<OX_P29); break;
		case 30:   OX_DDR30 |= (1<<OX_P30); break;
		case 31:   OX_DDR31 |= (1<<OX_P31); break;
		case 32:   OX_DDR32 |= (1<<OX_P32); break;
		case 33:   OX_DDR33 |= (1<<OX_P33); break;
		case 34:   OX_DDR34 |= (1<<OX_P34); break;
		case 35:   OX_DDR35 |= (1<<OX_P35); break;
		case 36:   OX_DDR36 |= (1<<OX_P36); break;
		case 37:   OX_DDR37 |= (1<<OX_P37); break;
		case 38:   OX_DDR38 |= (1<<OX_P38); break;
		case 39:   OX_DDR39 |= (1<<OX_P39); break;
		case 40:   OX_DDR40 |= (1<<OX_P40); break;
		case 41:   OX_DDR41 |= (1<<OX_P41); break;
		case 42:   OX_DDR42 |= (1<<OX_P42); break;
		case 43:   OX_DDR43 |= (1<<OX_P43); break;
		case 44:   OX_DDR44 |= (1<<OX_P44); break;
		default:   return RSP_UNKOWN_PIN;
		}
		return RSP_OK;
	}
	else
	{
		return RSP_UNKOWN_PIN;
	}
}

static uint8_t io_pin_set_direction_in (uint8_t pin)
{
	if ((pin >= 1 && pin <= 19) || (pin >= 26 && pin <= 44))
	{
		octopus.ports[pin] = PIN_IN;
		switch (pin)
		{
		case  1:  OX_DDR01 &= ~(1<<OX_P01); break;
		case  2:  OX_DDR02 &= ~(1<<OX_P02); break;
		case  3:  OX_DDR03 &= ~(1<<OX_P03); break;
		case  4:  OX_DDR04 &= ~(1<<OX_P04); break;
		case  5:  OX_DDR05 &= ~(1<<OX_P05); break;
		case  6:  OX_DDR06 &= ~(1<<OX_P06); break;
		case  7:  OX_DDR07 &= ~(1<<OX_P07); break;
		case  8:  OX_DDR08 &= ~(1<<OX_P08); break;
		case  9:  OX_DDR09 &= ~(1<<OX_P09); break;
		case 10:  OX_DDR10 &= ~(1<<OX_P10); break;
		case 11:  OX_DDR11 &= ~(1<<OX_P11); break;
		case 12:  OX_DDR12 &= ~(1<<OX_P12); break;
		case 13:  OX_DDR13 &= ~(1<<OX_P13); break;
		case 14:  OX_DDR14 &= ~(1<<OX_P14); break;
		case 15:  OX_DDR15 &= ~(1<<OX_P15); break;
		case 16:  OX_DDR16 &= ~(1<<OX_P16); break;
		case 17:  OX_DDR17 &= ~(1<<OX_P17); break;
		case 18:  OX_DDR18 &= ~(1<<OX_P18); break;
		case 19:  OX_DDR19 &= ~(1<<OX_P19); break;
		                     
		case 26:  OX_DDR26 &= ~(1<<OX_P26); break;
		case 27:  OX_DDR27 &= ~(1<<OX_P27); break;
		case 28:  OX_DDR28 &= ~(1<<OX_P28); break;
		case 29:  OX_DDR29 &= ~(1<<OX_P29); break;
		case 30:  OX_DDR30 &= ~(1<<OX_P30); break;
		case 31:  OX_DDR31 &= ~(1<<OX_P31); break;
		case 32:  OX_DDR32 &= ~(1<<OX_P32); break;
		case 33:  OX_DDR33 &= ~(1<<OX_P33); break;
		case 34:  OX_DDR34 &= ~(1<<OX_P34); break;
		case 35:  OX_DDR35 &= ~(1<<OX_P35); break;
		case 36:  OX_DDR36 &= ~(1<<OX_P36); break;
		case 37:  OX_DDR37 &= ~(1<<OX_P37); break;
		case 38:  OX_DDR38 &= ~(1<<OX_P38); break;
		case 39:  OX_DDR39 &= ~(1<<OX_P39); break;
		case 40:  OX_DDR40 &= ~(1<<OX_P40); break;
		case 41:  OX_DDR41 &= ~(1<<OX_P41); break;
		case 42:  OX_DDR42 &= ~(1<<OX_P42); break;
		case 43:  OX_DDR43 &= ~(1<<OX_P43); break;
		case 44:  OX_DDR44 &= ~(1<<OX_P44); break;
		default:  return RSP_UNKOWN_PIN;
		}
		return RSP_OK;
	}
	else
	{
		return RSP_UNKOWN_PIN;
	}
}

static uint8_t io_set_pin (uint8_t pin, uint8_t value)
{
	if (octopus.ports[pin] == PIN_OUT)
	{
		if (value)
		{
			switch (pin)
			{
			case  1:  OX_PORT01 |= (1<<OX_P01); break;
			case  2:  OX_PORT02 |= (1<<OX_P02); break;
			case  3:  OX_PORT03 |= (1<<OX_P03); break;
			case  4:  OX_PORT04 |= (1<<OX_P04); break;
			case  5:  OX_PORT05 |= (1<<OX_P05); break;
			case  6:  OX_PORT06 |= (1<<OX_P06); break;
			case  7:  OX_PORT07 |= (1<<OX_P07); break;
			case  8:  OX_PORT08 |= (1<<OX_P08); break;
			case  9:  OX_PORT09 |= (1<<OX_P09); break;
			case 10:  OX_PORT10 |= (1<<OX_P10); break;
			case 11:  OX_PORT11 |= (1<<OX_P11); break;
			case 12:  OX_PORT12 |= (1<<OX_P12); break;
			case 13:  OX_PORT13 |= (1<<OX_P13); break;
			case 14:  OX_PORT14 |= (1<<OX_P14); break;
			case 15:  OX_PORT15 |= (1<<OX_P15); break;
			case 16:  OX_PORT16 |= (1<<OX_P16); break;
			case 17:  OX_PORT17 |= (1<<OX_P17); break;
			case 18:  OX_PORT18 |= (1<<OX_P18); break;
			case 19:  OX_PORT19 |= (1<<OX_P19); break;
			                      
			case 26:  OX_PORT26 |= (1<<OX_P26); break;
			case 27:  OX_PORT27 |= (1<<OX_P27); break;
			case 28:  OX_PORT28 |= (1<<OX_P28); break;
			case 29:  OX_PORT29 |= (1<<OX_P29); break;
			case 30:  OX_PORT30 |= (1<<OX_P30); break;
			case 31:  OX_PORT31 |= (1<<OX_P31); break;
			case 32:  OX_PORT32 |= (1<<OX_P32); break;
			case 33:  OX_PORT33 |= (1<<OX_P33); break;
			case 34:  OX_PORT34 |= (1<<OX_P34); break;
			case 35:  OX_PORT35 |= (1<<OX_P35); break;
			case 36:  OX_PORT36 |= (1<<OX_P36); break;
			case 37:  OX_PORT37 |= (1<<OX_P37); break;
			case 38:  OX_PORT38 |= (1<<OX_P38); break;
			case 39:  OX_PORT39 |= (1<<OX_P39); break;
			case 40:  OX_PORT40 |= (1<<OX_P40); break;
			case 41:  OX_PORT41 |= (1<<OX_P41); break;
			case 42:  OX_PORT42 |= (1<<OX_P42); break;
			case 43:  OX_PORT43 |= (1<<OX_P43); break;
			case 44:  OX_PORT44 |= (1<<OX_P44); break;
			default:  return RSP_UNKOWN_PIN;
			}
		}
		else
		{
			switch (pin)
			{
			case  1:  OX_PORT01 &= ~(1<<OX_P01); break;
			case  2:  OX_PORT02 &= ~(1<<OX_P02); break;
			case  3:  OX_PORT03 &= ~(1<<OX_P03); break;
			case  4:  OX_PORT04 &= ~(1<<OX_P04); break;
			case  5:  OX_PORT05 &= ~(1<<OX_P05); break;
			case  6:  OX_PORT06 &= ~(1<<OX_P06); break;
			case  7:  OX_PORT07 &= ~(1<<OX_P07); break;
			case  8:  OX_PORT08 &= ~(1<<OX_P08); break;
			case  9:  OX_PORT09 &= ~(1<<OX_P09); break;
			case 10:  OX_PORT10 &= ~(1<<OX_P10); break;
			case 11:  OX_PORT11 &= ~(1<<OX_P11); break;
			case 12:  OX_PORT12 &= ~(1<<OX_P12); break;
			case 13:  OX_PORT13 &= ~(1<<OX_P13); break;
			case 14:  OX_PORT14 &= ~(1<<OX_P14); break;
			case 15:  OX_PORT15 &= ~(1<<OX_P15); break;
			case 16:  OX_PORT16 &= ~(1<<OX_P16); break;
			case 17:  OX_PORT17 &= ~(1<<OX_P17); break;
			case 18:  OX_PORT18 &= ~(1<<OX_P18); break;
			case 19:  OX_PORT19 &= ~(1<<OX_P19); break;
			                      
			case 26:  OX_PORT26 &= ~(1<<OX_P26); break;
			case 27:  OX_PORT27 &= ~(1<<OX_P27); break;
			case 28:  OX_PORT28 &= ~(1<<OX_P28); break;
			case 29:  OX_PORT29 &= ~(1<<OX_P29); break;
			case 30:  OX_PORT30 &= ~(1<<OX_P30); break;
			case 31:  OX_PORT31 &= ~(1<<OX_P31); break;
			case 32:  OX_PORT32 &= ~(1<<OX_P32); break;
			case 33:  OX_PORT33 &= ~(1<<OX_P33); break;
			case 34:  OX_PORT34 &= ~(1<<OX_P34); break;
			case 35:  OX_PORT35 &= ~(1<<OX_P35); break;
			case 36:  OX_PORT36 &= ~(1<<OX_P36); break;
			case 37:  OX_PORT37 &= ~(1<<OX_P37); break;
			case 38:  OX_PORT38 &= ~(1<<OX_P38); break;
			case 39:  OX_PORT39 &= ~(1<<OX_P39); break;
			case 40:  OX_PORT40 &= ~(1<<OX_P40); break;
			case 41:  OX_PORT41 &= ~(1<<OX_P41); break;
			case 42:  OX_PORT42 &= ~(1<<OX_P42); break;
			case 43:  OX_PORT43 &= ~(1<<OX_P43); break;
			case 44:  OX_PORT44 &= ~(1<<OX_P44); break;
			default:  return RSP_UNKOWN_PIN;
			}
		}
		return RSP_OK;
	}
	else
	{
		return RSP_WRONG_PIN_CONFIG;
	}
}

static uint8_t io_get_pin (uint8_t pin, uint8_t *value)
{
	*value = 0;
	if (octopus.ports[pin] == PIN_IN)
	{
		switch (pin)
		{
		case  1:  if (OX_PIN01 & (1<<OX_P01)) *value=1; break;
		case  2:  if (OX_PIN02 & (1<<OX_P02)) *value=1; break;
		case  3:  if (OX_PIN03 & (1<<OX_P03)) *value=1; break;
		case  4:  if (OX_PIN04 & (1<<OX_P04)) *value=1; break;
		case  5:  if (OX_PIN05 & (1<<OX_P05)) *value=1; break;
		case  6:  if (OX_PIN06 & (1<<OX_P06)) *value=1; break;
		case  7:  if (OX_PIN07 & (1<<OX_P07)) *value=1; break;
		case  8:  if (OX_PIN08 & (1<<OX_P08)) *value=1; break;
		case  9:  if (OX_PIN09 & (1<<OX_P09)) *value=1; break;
		case 10:  if (OX_PIN10 & (1<<OX_P10)) *value=1; break;
		case 11:  if (OX_PIN11 & (1<<OX_P11)) *value=1; break;
		case 12:  if (OX_PIN12 & (1<<OX_P12)) *value=1; break;
		case 13:  if (OX_PIN13 & (1<<OX_P13)) *value=1; break;
		case 14:  if (OX_PIN14 & (1<<OX_P14)) *value=1; break;
		case 15:  if (OX_PIN15 & (1<<OX_P15)) *value=1; break;
		case 16:  if (OX_PIN16 & (1<<OX_P16)) *value=1; break;
		case 17:  if (OX_PIN17 & (1<<OX_P17)) *value=1; break;
		case 18:  if (OX_PIN18 & (1<<OX_P18)) *value=1; break;
		case 19:  if (OX_PIN19 & (1<<OX_P19)) *value=1; break;
		                        
		case 26:  if (OX_PIN26 & (1<<OX_P26)) *value=1; break;
		case 27:  if (OX_PIN27 & (1<<OX_P27)) *value=1; break;
		case 28:  if (OX_PIN28 & (1<<OX_P28)) *value=1; break;
		case 29:  if (OX_PIN29 & (1<<OX_P29)) *value=1; break;
		case 30:  if (OX_PIN30 & (1<<OX_P30)) *value=1; break;
		case 31:  if (OX_PIN31 & (1<<OX_P31)) *value=1; break;
		case 32:  if (OX_PIN32 & (1<<OX_P32)) *value=1; break;
		case 33:  if (OX_PIN33 & (1<<OX_P33)) *value=1; break;
		case 34:  if (OX_PIN34 & (1<<OX_P34)) *value=1; break;
		case 35:  if (OX_PIN35 & (1<<OX_P35)) *value=1; break;
		case 36:  if (OX_PIN36 & (1<<OX_P36)) *value=1; break;
		case 37:  if (OX_PIN37 & (1<<OX_P37)) *value=1; break;
		case 38:  if (OX_PIN38 & (1<<OX_P38)) *value=1; break;
		case 39:  if (OX_PIN39 & (1<<OX_P39)) *value=1; break;
		case 40:  if (OX_PIN40 & (1<<OX_P40)) *value=1; break;
		case 41:  if (OX_PIN41 & (1<<OX_P41)) *value=1; break;
		case 42:  if (OX_PIN42 & (1<<OX_P42)) *value=1; break;
		case 43:  if (OX_PIN43 & (1<<OX_P43)) *value=1; break;
		case 44:  if (OX_PIN44 & (1<<OX_P44)) *value=1; break;
		default:  return RSP_UNKOWN_PIN;
		}
		return RSP_OK;
	}
	else
	{
		return RSP_WRONG_PIN_CONFIG;
	}
}

static uint8_t io_pin_set_direction_tri (uint8_t pin)
{
	if ((pin >= 1 && pin <= 19) || (pin >= 26 && pin <= 44))
	{
//		octopus.ports[pin] = PIN_TRI;			// just a special PIN_IN type
//		io_pin_set_direction_out(pin);			// kh: should be input !?
		io_pin_set_direction_in (pin);
		io_set_pin (pin, 1);
		return RSP_OK;
	}
	else
	{
		return RSP_UNKOWN_PIN;
	}
}

//////////////////////////////////////////////////////////////////////////////

#define RSP_UNKOWN_PORT		RSP_UNKOWN_PIN	// TBD

static uint8_t io_port_set_direction_out (uint8_t port, uint8_t mask)
{
//    octopus.ports[pin] = PIN_OUT;
	switch (port)
	{
      case  1:   DDRB = mask; break;
      case  2:   DDRC = mask; break; // PC7 = /CS (output) - do we need to mask this ?
      case  3:   DDRD = mask; break;
      case  4:   DDRE = mask; break; // PE4 = INT4 (input) - do we need to mask this ?
      case  5:   DDRF = mask; break;
      default:   return RSP_UNKOWN_PIN;
	}
	return RSP_OK;
}

static uint8_t io_set_port (uint8_t port, uint8_t value)
{
	switch (port)
	{
      case  1:   PORTB = value; break;
      case  2:   PORTC = value; break; // PC7 = /CS
      case  3:   PORTD = value; break;
      case  4:   PORTE = value; break; // PE4 = INTR 
      case  5:   PORTF = value; break;
      default:   return RSP_UNKOWN_PIN;
	}
	return RSP_OK;
}

static uint8_t io_get_port (uint8_t port, uint8_t *pvalue)
{
	uint8_t value;

	*pvalue = 0;
	switch (port)
	{
      case  1:   value = PINB; break;
      case  2:   value = PINC; break; // PC7 = /CS
      case  3:   value = PIND; break;
      case  4:   value = PINE; break; // PE4 = INTR 
      case  5:   value = PINF; break;
      default:   return RSP_UNKOWN_PORT;
	}
	*pvalue = value;
	return RSP_OK;
}

//////////////////////////////////////////////////////////////////////////////

uint8_t io_init_pin (uint8_t pin)
{
	if ((pin >= 1 && pin <= 19) || (pin >= 26 && pin <= 44))
	{
		io_pin_set_direction_out (pin);
		return RSP_OK;
	}
	return RSP_UNKOWN_PIN;
}

//////////////////////////////////////////////////////////////////////////////
// _usb functions

//static void io_port_set_direction_in  (uint8_t port, uint8_t mask){}
//static void io_port_set_direction_tri (uint8_t port, uint8_t mask){}

//static void io_port_get_bulk(uint8_t port, uint8_t number){}
//static void io_port_set_bulk(uint8_t port, uint8_t number, uint8_t * buf){}
//static void io_pin_set_bulk(uint8_t pin, uint8_t number, uint8_t * buf){}
//static void io_pin_get_bulk(uint8_t pin, uint8_t number){}

static void io_init_port_usb (uint8_t port)
{
}

static void io_port_get_usb (uint8_t port)
{
	uint8_t value;

	answer[1] = io_get_port (port, &value);
	answer[2] = value;
	CommandAnswer (3);
}

static void io_port_set_usb (uint8_t port, uint8_t mask)
{
	answer[1] = io_set_port (port, mask);
	answer[2] = 0;
	CommandAnswer (3);
}

static void io_port_set_direction_out_usb (uint8_t port, uint8_t mask)
{
	answer[1] = io_port_set_direction_out (port, mask);
	answer[2] = 0;
	CommandAnswer (3);
}

static void io_port_set_direction_in_usb (uint8_t port, uint8_t mask)
{
}
static void io_port_set_direction_tri_usb (uint8_t port, uint8_t mask)
{
}

static void io_init_pin_usb (uint8_t pin)
{
	answer[1] = io_init_pin (pin);
	answer[2] = 0;
	CommandAnswer (3);
}

static void io_pin_set_direction_out_usb (uint8_t pin)
{
	answer[1] = io_pin_set_direction_out (pin);
	answer[2] = 0;
	CommandAnswer (3);
}

static void io_pin_set_direction_in_usb (uint8_t pin)
{
	answer[1] = io_pin_set_direction_in (pin);
	answer[2] = 0;
	CommandAnswer (3);
}

static void io_pin_set_direction_tri_usb (uint8_t pin)
{
	answer[1] = io_pin_set_direction_tri (pin);
	answer[2] = 0;
	CommandAnswer (3);
}

static void io_pin_set_usb (uint8_t pin, uint8_t value)
{
	answer[1] = io_set_pin (pin, value);
	answer[2] = 0;
	CommandAnswer (3);
}

static void io_pin_get_usb (uint8_t pin)
{
	uint8_t value;

	answer[1] = io_get_pin (pin, &value);
	answer[2] = value;
	CommandAnswer (3);			// kh: ??
}

//////////////////////////////////////////////////////////////////////////////

void io_parser (uint8_t *buf)
{
	// prepare the response
	answer[0] = buf[0];

	switch (buf[0])
	{
	case CMD_IO_INIT_PIN:
		io_init_pin_usb (buf[2]);
		break;
	case CMD_IO_PIN_DIRECTION_IN:
		io_pin_set_direction_in_usb (buf[2]);
		break;
	case CMD_IO_PIN_DIRECTION_OUT:
		io_pin_set_direction_out_usb (buf[2]);
		break;
	case CMD_IO_PIN_DIRECTION_TRI:
		io_pin_set_direction_tri_usb (buf[2]);
		break;
	case CMD_IO_PIN_SET:
		io_pin_set_usb (buf[2], buf[3]);
		break;
	case CMD_IO_PIN_GET:
		io_pin_get_usb (buf[2]);
		break;

	case CMD_IO_INIT_PORT:
		io_init_port_usb (buf[2]);
		break;
	case CMD_IO_PORT_DIRECTION_IN:
		io_port_set_direction_in_usb (buf[2], buf[3]);
		break;
	case CMD_IO_PORT_DIRECTION_OUT:
		io_port_set_direction_out_usb (buf[2], buf[3]);
		break;
	case CMD_IO_PORT_DIRECTION_TRI:
		io_port_set_direction_tri_usb (buf[2], buf[3]);
		break;
	case CMD_IO_PORT_SET:
		io_port_set_usb (buf[2], buf[3]);
		break;
	case CMD_IO_PORT_GET:
		io_port_get_usb (buf[2]);
		break;

	default:
		answer[1] = RSP_UNKOWN_CMD;
		answer[2] = 0;
		CommandAnswer (3);
	}
}

//////////////////////////////////////////////////////////////////////////////

void io_init (void)
{
	// is this really what we want ?
	int     i;

	for (i = 1; i <= 19; i++)
		io_init_pin (i);
	for (i = 26; i <= 44; i++)
		io_init_pin (i);
}
